#include "table.h"
#include "flowgraph.h"
#include "temp.h"

G_table def = NULL, use = NULL;
G_table node_ins = NULL;

Temp_tempList FG_def(G_node n)
{
    return G_look(def, n);
};

Temp_tempList FG_use(G_node n)
{
    return G_look(use, n);
};

bool FG_isMove(G_node n)
{
    AS_instr instr = G_look(node_ins,n);
    return (instr->kind == I_MOVE);
};

AS_instr FG_getInstr(G_node n)
{
    return (AS_instr)G_look(node_ins, n);
}

G_graph FG_AssemFlowGraph(AS_instrList il)
{
    G_graph graph = G_Graph();
    G_node old = NULL, new = NULL;
    G_nodeList list = NULL, ptr = NULL;
    AS_instrList instr = il;
    TAB_table ins_node = TAB_empty();
    bool isJump = FALSE;

    use = G_empty();
    def = G_empty();
    node_ins = G_empty();

    // create nodes
    while (instr)
    {
        new = G_Node(graph, NULL);
        G_enter(node_ins, new, instr->head);

        if (instr->head->kind == I_LABEL)
            TAB_enter(ins_node, 
                instr->head->u.LABEL.label, 
                new);

        instr = instr->tail;
    }

    list = G_nodes(graph);
    ptr = list;
    while(ptr)
    {
        AS_instr instr;
        new = ptr->head;
        instr = G_look(node_ins, new);
        assert(instr);
        
        // create edges
        if (!isJump && old)
        {
            G_addEdge(old, new);
        }

        if (instr->kind == I_OPER
            && instr->u.OPER.jumps )         // is a jump
        {
            Temp_labelList list = instr->u.OPER.jumps->labels;
            G_node target = NULL;

            while(list)
            {
                target = TAB_look(ins_node, list->head);
                G_addEdge(new, target);
                list = list->tail;
            }
            isJump = TRUE;
        }
        else
            isJump = FALSE;
        
        // now deal with the var
        if (instr->kind == I_OPER)
        {
            if (instr->u.OPER.dst)
                G_enter(def, new, instr->u.OPER.dst);
            if (instr->u.OPER.src)
                G_enter(use, new, instr->u.OPER.src);
            old = new;
            ptr = ptr->tail;
            continue;
        }

        if (instr->kind == I_MOVE)
        {
            if (instr->u.MOVE.dst)
                G_enter(def, new, instr->u.MOVE.dst);
            if (instr->u.MOVE.src)
                G_enter(use, new, instr->u.MOVE.src);

            old = new;
            ptr = ptr->tail;
            continue;
        }

        old = new;    
        ptr = ptr->tail;
    }
    return graph;
};
